package lelouet.sh3d;

import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.ResourceBundle;

import com.eteks.sweethome3d.model.CatalogPieceOfFurniture;
import com.eteks.sweethome3d.model.Content;

/**
 * Iterates over a *.properties file and translates it to a iterator of
 * {@link CatalogPieceOfFurniture}<br />
 * NOT Thread-safe : do NOt use it in two threads.
 */
public class FurnitureBundleParser implements Iterable<CatalogPieceOfFurniture> {

  protected static enum iterStates {
    notChecked, noMore, gotNext
  }

  public final Map<CatalogPieceOfFurniture, String> categories = new HashMap<CatalogPieceOfFurniture, String>();

  protected ResourceBundle bundle;

  /** {@link Content} will be searched in that {@link ClassLoader} first */
  protected ClassLoader baseContainer = null;

  /**
   * if {@link #baseContainer} is null, then {@link Content} will be searched in
   * that URL first. If both are null, then it will be searched in current
   * classpath.
   */
  protected URL resourceLocation = null;

  protected iterStates iterState = iterStates.notChecked;

  protected CatalogPieceOfFurniture next = null;

  /**
   * if one iterator has been called, and it is in memory and has still elements
   * to iterate over
   */
  protected Iterator<CatalogPieceOfFurniture> myIterator = null;

  public FurnitureBundleParser(String bundleName, ClassLoader baseContainer) {
    bundle = ResourceBundle.getBundle(bundleName);
    this.baseContainer = baseContainer;
  }

  /**
   * @param bundleName
   *          the name of the *.properties file ; actually, the path toget it
   * @param baseResourceLocation
   *          the url of the file in which to look for files used by
   *          {@link CatalogPieceOfFurniture}s.
   */
  public FurnitureBundleParser(String bundleName, URL baseResourceLocation) {
    bundle = ResourceBundle.getBundle(bundleName);
    resourceLocation = baseResourceLocation;
  }

  private boolean isBeingIterated() {
    return myIterator != null;
  }

  @Override
  public Iterator<CatalogPieceOfFurniture> iterator() {
    if (isBeingIterated()) {
      throw new UnsupportedOperationException(
          "a furniture Bundle can only be iterated once at a time ");
    }
    return new Iterator<CatalogPieceOfFurniture>() {

      protected int lastPosChecked = 0;

      @Override
      public boolean hasNext() {
        if (iterState != iterStates.notChecked) {
          return iterState == iterStates.gotNext;
        } else {
          lastPosChecked++;
          if (baseContainer != null) {
            // next = Utils.readPieceOfFurniture(bundle, pos, baseContainer);
          } else {
            next = Utils.readPieceOfFurniture(bundle, lastPosChecked,
                resourceLocation, categories);
          }
          if (next == null) {
            iterState = iterStates.noMore;
            onEndReaching();
            return false;
          } else {
            iterState = iterStates.gotNext;
            return true;
          }
        }
      }

      @Override
      public CatalogPieceOfFurniture next() {
        if (hasNext()) {
          CatalogPieceOfFurniture ret = next;
          next = null;
          iterState = iterStates.notChecked;
          return ret;
        } else {
          throw new NoSuchElementException();
        }
      }

      /**
       * specifies that the iterator has reached the end of the elements to the
       * furnitureBundleIterator
       */
      protected void onEndReaching() {
        myIterator = null;
      }

      @Override
      public void remove() {
        throw new UnsupportedOperationException(
            "read-only iterator on furniture bundle iterator");
      }
    };
  }

}
